package yl.hs.bmipfull.service.impl;

import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.PushPayload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import yl.hs.bmipfull.annotations.DBField;
import yl.hs.bmipfull.annotations.DBTable;
import yl.hs.bmipfull.daos.salemanage.ICustomerUserDao;
import yl.hs.bmipfull.daos.salemanage.ILinkerInfoDao;
import yl.hs.bmipfull.daos.salemanage.ISaleContractDao;
import yl.hs.bmipfull.daos.system.*;
import yl.hs.bmipfull.pojo.salemanage.CustomerInfoEntity;
import yl.hs.bmipfull.pojo.salemanage.CustomerUserEntity;
import yl.hs.bmipfull.pojo.salemanage.SaleContractEntity;
import yl.hs.bmipfull.pojo.system.DutyInfoEntity;
import yl.hs.bmipfull.pojo.system.GlobalSearchEntity;
import yl.hs.bmipfull.pojo.system.SiteMessageMainEntity;
import yl.hs.bmipfull.pojo.system.SiteMessageReceiptEntity;
import yl.hs.bmipfull.utils.*;
import yl.hs.bmipfull.utils.datastate.ActionType;
import yl.hs.bmipfull.utils.datastate.MsgReceiveType;
import yl.hs.bmipfull.utils.datastate.MsgType;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 谢景广
 * @category
 */
public class BaseService {

    @Autowired
    protected ICoreDataTagDao coreTagDao;
    @Autowired
    IPojoSvcDao psDao;

    @Autowired
    IGlobalSearchDao gsDao;
    protected SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    protected SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * @param classType 实体类实例
     * @return 新的数据编号
     * @throws Exception 获取编号时发生的异常
     * @category 获取新的标识
     */
    protected String queryNewSN(Class<?> classType) {
        return queryNewSN(classType, 0, false);
    }

    /**
     * @param classType 实体类实例
     * @return 新的数据编号
     * @throws Exception 获取编号时发生的异常
     * @category 获取新的标识
     */
    protected String queryNewTempSN(Class<?> classType) {
        return queryNewSN(classType, 0, true);
    }

    /**
     * @param classType    实体类实例
     * @param appendLength 附加实体类数量
     * @return 新的数据编号
     * @category 获取新的标识
     */
    protected String queryNewSN(Class<?> classType, int appendLength, boolean temp) {

        var dbTable = classType.getAnnotation(DBTable.class);
        DBField field = Tl.getSerialNoDBField(classType);
        SimpleDateFormat format = new SimpleDateFormat("yyMMdd");
        String dayCode = format.format(new Date());
        String maxSn = psDao.queryMaxSN(dbTable.mapCode(), field.mapCode(), String.format("%s%s%s", (temp ? "TEMP" : field.snPrefix().toUpperCase()), dayCode, getSiteDataFlag()));
        int max = 0;
        if (!Tl.isEmpty(maxSn)) {
            var maxStr = maxSn.substring((temp ? "TEMP".length() : field.snPrefix().length()) + dayCode.length());
            if (!Tl.isEmpty(maxStr)) {
                maxStr = maxStr.replaceAll("[A-Za-z]+", "");
                max = Integer.parseInt(maxStr);
            }
        }
        max = (max + appendLength + 1);
        ICache cache = CacheFactory.getCache();
        var key = String.format("SN_%s_%s", dbTable.mapCode(), (temp ? "TEMP" : field.snPrefix().toUpperCase()));
        var oldMax = cache.get(key);
        if (oldMax != null) {
            int oldMaxSN = Integer.parseInt(oldMax.toString());
            if (oldMaxSN == max) {
                max++;
            }
            if (max < oldMaxSN && appendLength > 0) {
                max = oldMaxSN + 1 + appendLength;
            }
            cache.add(key, max);
        }
        return String.format("%s%s%s", (temp ? "TEMP" : field.snPrefix().toUpperCase()), dayCode,
                String.format("%06d", max));
    }

    protected String queryNewSN(Class<?> cls, String maxSN, int appendLength) {
        var dbTable = cls.getAnnotation(DBTable.class);
        int max = 0;
        DBField field = Tl.getSerialNoDBField(cls);
        SimpleDateFormat format = new SimpleDateFormat("yyMMdd");
        String dayCode = format.format(new Date());
        if (!Tl.isEmpty(maxSN)) {
            var maxStr = maxSN.substring(field.snPrefix().length() + dayCode.length());
            if (!Tl.isEmpty(maxStr)) {
                maxStr = maxStr.replaceAll("[A-Za-z]+", "");
                max = Integer.parseInt(maxStr);
            }
        }
        max = (max + appendLength);
        ICache cache = CacheFactory.getCache();
        var key = String.format("SN_%s_%s", dbTable.mapCode(), field.snPrefix().toUpperCase());
        var oldMax = cache.get(key);
        if (oldMax != null) {
            int oldMaxSN = Integer.parseInt(oldMax.toString());
            if (oldMaxSN == max) {
                max++;
            }
            if (max < oldMaxSN && appendLength > 0) {
                max = oldMaxSN + 1 + appendLength;
            }
            cache.add(key, max);
        }
        return String.format("%s%s%s%s", field.snPrefix().toUpperCase(), dayCode, getSiteDataFlag(),
                String.format("%06d", max));
    }

    private String getSiteDataFlag() {
        try {
            var siteDataFlag = HsApp.getSystemSet(CK.SiteDataFlag);
            if (!Tl.isEmpty(siteDataFlag)) {
                if (siteDataFlag.length() > 4) {
                    siteDataFlag = siteDataFlag.substring(0, 4);
                }
            } else {
                siteDataFlag = "";
            }
            return siteDataFlag;
        } catch (Exception ee) {
            return "";
        }
    }

    /**
     * @param code 标识头部代码
     * @return 新的数据编号
     * @throws Exception 获取编号时发生的异常
     * @category 获取新的标识
     */
    protected String queryNewSN(String maxSn, String code) {
        int max = 0;
        if (maxSn != null && !"".equals(maxSn)) {
            var maxStr = maxSn.substring(code.length() + 6);
            maxStr = maxStr.replaceAll("[A-Za-z]+", "");
            max = Integer.parseInt(maxStr);
        }
        SimpleDateFormat format = new SimpleDateFormat("yyMMdd");

        return String.format("%s%s%s%s", code, format.format(new Date()), getSiteDataFlag(),
                String.format("%06d", (max + 1)));
    }

    protected Integer saveGS(String sn, String title, String body, Object obj) {
        return saveGS(sn, title, body, obj, null, null);
    }

    protected Integer saveShareGS(String sn, String title, String body, Object obj, String shareCode) {
        return saveGS(sn, title, body, obj, null, shareCode);
    }

    protected Integer saveUserGS(String sn, String title, String body, Object obj, String userSN) {
        return saveGS(sn, title, body, obj, userSN, null);
    }

    protected Integer saveGS(String sn, String title, String body, Object obj, String userSN, String shareCode) {
        gsDao.deleteDataByDataSNList(Arrays.stream(new String[]{sn}).toList());
        var dbTable = obj.getClass().getAnnotation(DBTable.class);
        var data = new GlobalSearchEntity();
        setGSData(sn, title, body, userSN, shareCode, data, dbTable);
        return gsDao.insertNew(data);
    }

    private void setGSData(String sn, String title, String body, String userSN, String shareCode, GlobalSearchEntity data, DBTable dbTable) {
        if (!Tl.isEmpty(userSN)) {
            if (Tl.isEmpty(data.getUserSN())) {
                data.setUserSN(userSN);
            } else {
                data.setUserSN(String.format("%s,%s", data.getUserSN(), userSN));
            }
        }
        if (!Tl.isEmpty(shareCode)) {
            var oldShareCode = data.getShareCode();
            List<String> codes = new ArrayList<>();
            if (!Tl.isEmpty(oldShareCode)) {
                var codeArray = oldShareCode.split(",");
                for (var code : codeArray) {
                    if (!codes.contains(code)) {
                        codes.add(code);
                    }
                }
            }
            var codeArray = shareCode.split(",");
            for (var code : codeArray) {
                if (!codes.contains(code)) {
                    codes.add(code);
                }
            }
            data.setShareCode(String.join(",", codes));
        }
        data.setDataSN(sn);
        data.setDataCode(dbTable.mapCode());
        data.setTitle(title);
        data.setBody(body);
        data.setDataType(dbTable.disName());
        data.setLastModify(new Date());
    }

    protected Integer deleteGs(String[] snArray) {
        return deleteGs(Arrays.stream(snArray).toList());
    }

    protected Integer deleteGs(List<String> snList) {
        return gsDao.deleteDataByDataSNList(snList);
    }

    protected String getActionDesc(ActionType action) {
        var actionDesc = "";
        switch (action) {
            case CREATE -> {
                actionDesc = "创建";
            }
            case DELETE -> {
                actionDesc = "删除";
            }
            case UPDATE -> {
                actionDesc = "更新";
            }
            case QUERY -> {
                actionDesc = "查询";
            }
            case IMPORT -> {
                actionDesc = "导入";
            }
            case EXPORT -> {
                actionDesc = "导出";
            }
            case LOGIN -> {
                actionDesc = "登录";
            }
            case PRINT -> {
                actionDesc = "打印";
            }
            case REVIEWED -> {
                actionDesc = "审核";
            }
            case UNREVIEWED -> {
                actionDesc = "取消审核";
            }
        }
        return actionDesc;
    }

    protected Integer sendMsg(String toUserSN, String title, String message) throws Exception {
        return sendMsg(MsgType.System, toUserSN, title, message);
    }

    protected Integer sendMsg(MsgType type, String toUserSN, String title, String message) throws Exception {
        return sendMsg(type, MsgReceiveType.User, toUserSN, title, message);
    }

    protected Integer sendMsg(MsgType type, MsgReceiveType toType, String toSN, String title, String message) throws Exception {
        var msg = new SiteMessageMainEntity();
        var receiver = new SiteMessageReceiptEntity();
        var msgSN = queryNewSN(SiteMessageMainEntity.class);
        msg.setMsgBody(message);
        msg.setSubject(title);
        msg.setMsgType(type.code);
        msg.setSendTime(new Date());
        msg.setSn(msgSN);
        if (type == MsgType.System) {
            msg.setSenderSN("");
            msg.setSerderName("系统");
        } else {
            var user = HsApp.getCurrent();
            if (user == null) {
                msg.setSenderSN("");
                msg.setSerderName("系统");
            } else {
                msg.setSenderSN(user.getUserSN());
                msg.setSerderName(user.getUserName());
            }
        }
        receiver.setMsgSN(msgSN);
        receiver.setReceiptType(toType.code);
        String[] snList = toSN.split(",");
        switch (toType) {

            case User -> {
                var user = userDao.findBySN(toSN);
                if (user != null) {
                    receiver.setReceipterName(user.getRealname());
                }
            }
            case Role -> {
                for (var str : snList) {
                    var role = roleDao.findBySN(toSN);
                    if (role != null) {
                        receiver.setReceipterName(receiver.getReceipterName() + "," + role.getRoleName());
                    }
                }

            }
            case Duty -> {
                for (var str : snList) {
                    var duty = dutyDao.findBySN(toSN);
                    if (duty != null) {
                        receiver.setReceipterName(receiver.getReceipterName() + "," + duty.getDutyName());
                    }
                }

            }
            case Organize -> {
                for (var str : snList) {
                    var org = orgDao.findBySN(toSN);
                    if (org != null) {
                        receiver.setReceipterName(receiver.getReceipterName() + "," + org.getFullName());
                    }
                }
            }
            case Anyone -> {
                receiver.setReceipterName("所有人");
            }
        }
        receiver.setReceipterSN(toSN);
        receiver.setReceiptTime(new Date());
        var mResult = msgDao.insertNew(msg);
        if (mResult > 0) {
            return receiptDao.insertNew(receiver);
        }
        return 0;
    }

    protected List<DutyInfoEntity> getUserDutyList(String userSN) {
        var dutyCode = Tl.getDBMapCode(DutyInfoEntity.class);
        var userDutyList = coreTagDao.queryByMainSn(userSN, dutyCode);
        return dutyDao.queryListBySNArray(userDutyList.stream().map(t -> t.getTagSN()).collect(Collectors.toList()));


    }

    public String getDepartSN() {
        var user = HsApp.getCurrent();
        if (user != null) {
            var dutyList = getUserDutyList(user.getUserSN());
            var st = new ArrayList<String>();
            if (dutyList.size() > 0) {
                for (int i = 0; i < dutyList.size(); i++) {
                    var orgCode = dutyList.get(i).getOrganizationCode().split(",");
                    if (orgCode.length > 0) {
                        for (int j = 0; j < orgCode.length; j++) {
                            if (!st.contains(orgCode[j])) {
                                st.add(orgCode[j]);
                            }
                        }
                    }
                }
            } else {
                return user.getOrganizationCode();
            }
            return String.join(",", st);
        }
        return "";
    }

    protected List<String> getConstructionContractSN() throws Exception {
        var user = HsApp.getCurrent();
        if (user == null) {
            throw new Exception("用户登录信息错误");
        }
        var customerUser = getConstructionCurrent();
        if (customerUser != null) {
            if (customerUser.getLinkType() == 0) {
                return contractDao.querySNListByCustomSN(user.getCompanySN());
            } else {
                return customerUserDao.queryContractSNByLinkSN(user.getUserSN(), Tl.getDBMapCode(SaleContractEntity.class));
            }
        } else {
            return customerUserDao.queryContractSNByLinkSN(user.getUserSN(), Tl.getDBMapCode(SaleContractEntity.class));
        }
    }

    protected CustomerUserEntity getConstructionCurrent() throws Exception {
        var user = HsApp.getCurrent();
        if (user == null) {
            throw new Exception("用户登录信息错误");
        }
        return customerUserDao.findByCustSNAndLinkSN(user.getUserSN(), user.getCompanySN());
    }


    protected void sendConstructMessage(String message, String contractSN, String title) {
        sendConstructMessage(message, contractSN, title, (short) 1);
    }

    protected void sendConstructMessage(String message, String contractSN, String title, short linkType) {
        var userSNList = new ArrayList<String>();
        var cUsers = customerUserDao.queryContractUsers(contractSN, Tl.getDBMapCode(SaleContractEntity.class));
        if (cUsers.size() > 0) {
            userSNList.addAll(cUsers.stream().filter(t -> t.getLinkType() == linkType || t.getLinkType() == 0).map(t -> t.getLinkerSN()).toList());
        }
        var contract = contractDao.findBySN(contractSN);
        if (contract != null) {
            var custUsers = customerUserDao.queryContractUsers(contract.getCustomerSN(), Tl.getDBMapCode(CustomerInfoEntity.class));
            if (custUsers.size() > 0) {
                userSNList.addAll(custUsers.stream().filter(t -> t.getLinkType() == 0).map(t -> t.getLinkerSN()).toList());
            }
        }
        if (userSNList.size() > 0) {
            var linkerList = linkerDao.findLinkerBySN(userSNList);
            if (linkerList.size() > 0) {
                var msg = new SiteMessageMainEntity();
                var receiver = new SiteMessageReceiptEntity();
                var msgSN = queryNewSN(SiteMessageMainEntity.class);
                msg.setMsgBody(message);
                var user = HsApp.getCurrent();
                msg.setSenderSN(user.getUserSN());
                msg.setSerderName(user.getUserName());
                msg.setSubject(title);
                msg.setMsgType(MsgType.System.code);
                msg.setSendTime(new Date());
                msg.setSn(msgSN);
                var result = msgDao.insertNew(msg);
                if (result > 0) {
                    var phoneCodes = new ArrayList<String>();
                    for (var r : linkerList) {
                        receiver.setReceipterName(r.getFullName());
                        receiver.setReceipterSN(r.getSn());
                        receiver.setReceiptType(MsgReceiveType.Construction.code);
                        receiver.setMsgSN(msg.getSn());
                        receiver.setReceiptTime(new Date());
                        receiptDao.insertNew(receiver);
                        if (!Tl.isEmpty(r.getPhoneCode())) {
                            phoneCodes.add(r.getPhoneCode());
                        }
                    }
                    if (phoneCodes.size() > 0) {
                        sendJGToRegistrationId(phoneCodes, title, title, message, "");
                    }
                }
            }
        }
    }

    protected void sendSysFeatherMessage(String message, String menuPagePath, String title) {
        var menu = menuInfoDao.queryByPagePath(menuPagePath);
        if (menu != null) {
            var roleSNList = authorizeDao.queryRoleSNByMenuSN(menu.getSn());
            if (roleSNList.size() > 0) {
                var roles = roleDao.queryRolesBySn(roleSNList);
                if (roles.size() > 0) {
                    var msg = new SiteMessageMainEntity();
                    var receiver = new SiteMessageReceiptEntity();
                    var msgSN = queryNewSN(SiteMessageMainEntity.class);
                    msg.setMsgBody(message);
                    var user = HsApp.getCurrent();
                    msg.setSenderSN(user.getUserSN());
                    msg.setSerderName(user.getUserName());
                    msg.setSubject(title);
                    msg.setMsgType(MsgType.System.code);
                    msg.setSendTime(new Date());
                    msg.setSn(msgSN);
                    var result = msgDao.insertNew(msg);
                    if (result > 0) {
                        for (var r : roles) {
                            receiver.setReceipterName(r.getRoleName());
                            receiver.setReceipterSN(r.getSn());
                            receiver.setReceiptType(MsgReceiveType.Role.code);
                            receiver.setMsgSN(msg.getSn());
                            receiver.setReceiptTime(new Date());
                            receiptDao.insertNew(receiver);
                        }
                    }
                }
            }
        }
    }

    protected Logger log = LoggerFactory.getLogger("BaseService");

    private int sendJGToRegistrationId(List<String> alias, String notification_title, String msg_title, String msg_content, String extrasparam) {
        JPushClient jPushClient = new JPushClient(HsApp.getSystemSet(CK.JGApp_Secret), HsApp.getSystemSet(CK.JGApp_Key));
        int result = 0;
        try {
            PushPayload pushPayload = JPushUtil.buildPushObject_all_alias_alertWithTitle(alias, notification_title, msg_title, msg_content, extrasparam);
            PushResult pushResult = jPushClient.sendPush(pushPayload);
            if (pushResult.getResponseCode() == 200) {
                result = 1;
            }
            log.info("[极光推送]PushResult result is " + pushResult);
        } catch (APIConnectionException e) {
            log.error("[极光推送]Connection error. Should retry later. ", e);

        } catch (APIRequestException e) {
            log.error("[极光推送]Error response from JPush server. Should review and fix it. ", e);
            log.info("[极光推送]HTTP Status: " + e.getStatus());
            log.info("[极光推送]Error Code: " + e.getErrorCode());
            log.info("[极光推送]Error Message: " + e.getErrorMessage());
        }

        return result;
    }

    @Autowired
    protected ILinkerInfoDao linkerDao;

    @Autowired
    protected ICustomerUserDao customerUserDao;

    @Autowired
    ISaleContractDao contractDao;

    @Autowired
    protected IAppSettingDao appSettingDao;

    @Autowired
    IUserInfoDao userDao;
    @Autowired
    IRoleInfoDao roleDao;
    @Autowired
    IDutyInfoDao dutyDao;
    @Autowired
    IOrganizationInfoDao orgDao;

    @Autowired
    ISiteMessageMainDao msgDao;

    @Autowired
    ISiteMessageReceiptDao receiptDao;

    @Autowired
    IMenuInfoDao menuInfoDao;

    @Autowired
    IAuthorizeDao authorizeDao;
}
